package com.itheima.utils.common;

import io.jsonwebtoken.*;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

public class JwtUtil {

    // TOKEN的有效期（3600秒 = 1小时）
    private static final long TOKEN_TIME_OUT = 3600 * 1000;  // 毫秒
    // 加密密钥（建议64位以上字符）
    private static final String TOKEN_ENCRY_KEY = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjYxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTA=";
    // 最小刷新间隔（300秒 = 5分钟）
    private static final long REFRESH_TIME = 300 * 1000;  // 毫秒

    /**
     * 生成Token（小程序端用，保持兼容）
     */
    public static String getToken(Long id) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", id);
        claims.put("userType", "MP_USER");  // 标识为小程序用户

        long currentTime = System.currentTimeMillis();
        return Jwts.builder()
                .setId(UUID.randomUUID().toString())
                .setIssuedAt(new Date(currentTime))
                .setSubject("system")
                .setIssuer("itheima")
                .setAudience("user")
                .compressWith(CompressionCodecs.GZIP)
                // 低版本JJWT：先指定算法，再指定密钥（与高版本相反）
                .signWith(SignatureAlgorithm.HS512, generalKey())  // 修正参数顺序
                .setExpiration(new Date(currentTime + TOKEN_TIME_OUT))
                .addClaims(claims)
                .compact();
    }

    /**
     * 生成Token（管理端用，支持角色和权限）
     * 
     * @param id 管理员ID
     * @param username 用户名
     * @param nickname 昵称
     * @param roles 角色列表
     * @param permissions 权限列表
     * @return JWT Token
     */
    public static String getAdminToken(Integer id, String username, String nickname, 
                                      List<String> roles, List<String> permissions) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", id);
        claims.put("username", username);
        claims.put("nickname", nickname);
        claims.put("userType", "ADMIN");  // 标识为管理员
        claims.put("roles", roles);
        claims.put("permissions", permissions);

        long currentTime = System.currentTimeMillis();
        return Jwts.builder()
                .setId(UUID.randomUUID().toString())
                .setIssuedAt(new Date(currentTime))
                .setSubject(username)
                .setIssuer("itheima")
                .setAudience("admin")
                .compressWith(CompressionCodecs.GZIP)
                .signWith(SignatureAlgorithm.HS512, generalKey())
                .setExpiration(new Date(currentTime + TOKEN_TIME_OUT))
                .addClaims(claims)
                .compact();
    }

    /**
     * 生成Token（通用方法，自定义claims）
     * 
     * @param claims 自定义数据
     * @param expireTime 过期时间（毫秒）
     * @return JWT Token
     */
    public static String getToken(Map<String, Object> claims, Long expireTime) {
        long currentTime = System.currentTimeMillis();
        long expire = expireTime != null ? expireTime : TOKEN_TIME_OUT;
        
        return Jwts.builder()
                .setId(UUID.randomUUID().toString())
                .setIssuedAt(new Date(currentTime))
                .setSubject("system")
                .setIssuer("itheima")
                .compressWith(CompressionCodecs.GZIP)
                .signWith(SignatureAlgorithm.HS512, generalKey())
                .setExpiration(new Date(currentTime + expire))
                .addClaims(claims)
                .compact();
    }

    /**
     * 解析Token
     */
    private static Jws<Claims> parseToken(String token) throws JwtException {
        return Jwts.parser()
                .setSigningKey(generalKey())  // 验证密钥
                .parseClaimsJws(token);
    }

    /**
     * 获取Token中的自定义数据
     */
    public static Claims getClaims(String token) {
        try {
            return parseToken(token).getBody();
        } catch (ExpiredJwtException e) {
            return e.getClaims();
        } catch (JwtException e) {
            return null;
        }
    }

    /**
     * 验证Token状态
     * 
     * @param claims Token中的claims
     * @return -1:有效无需刷新, 0:可刷新, 1:已过期, 2:无效
     */
    public static int verifyToken(Claims claims) {
        if (claims == null) {
            return 2;  // 无效
        }
        Date expiration = claims.getExpiration();
        long now = System.currentTimeMillis();
        if (expiration == null) {
            return 2;
        }
        if (expiration.after(new Date(now + REFRESH_TIME))) {
            return -1;  // 有效无需刷新
        } else if (expiration.after(new Date(now))) {
            return 0;   // 可刷新
        } else {
            return 1;   // 已过期
        }
    }

    /**
     * 验证Token是否有效
     * 
     * @param token JWT Token
     * @return true:有效, false:无效
     */
    public static boolean validateToken(String token) {
        try {
            Claims claims = getClaims(token);
            if (claims == null) {
                return false;
            }
            int status = verifyToken(claims);
            // -1 和 0 都表示token有效
            return status == -1 || status == 0;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 从Token中获取用户ID
     * 
     * @param token JWT Token
     * @return 用户ID
     */
    public static Integer getUserId(String token) {
        Claims claims = getClaims(token);
        if (claims == null) {
            return null;
        }
        Object id = claims.get("id");
        if (id instanceof Integer) {
            return (Integer) id;
        } else if (id instanceof Long) {
            return ((Long) id).intValue();
        }
        return null;
    }

    /**
     * 从Token中获取用户类型
     * 
     * @param token JWT Token
     * @return 用户类型：MP_USER(小程序用户) 或 ADMIN(管理员)
     */
    public static String getUserType(String token) {
        Claims claims = getClaims(token);
        if (claims == null) {
            return null;
        }
        return (String) claims.get("userType");
    }

    /**
     * 判断是否为管理员Token
     * 
     * @param token JWT Token
     * @return true:管理员, false:非管理员
     */
    public static boolean isAdmin(String token) {
        return "ADMIN".equals(getUserType(token));
    }

    /**
     * 从Token中获取权限列表
     * 
     * @param token JWT Token
     * @return 权限列表
     */
    @SuppressWarnings("unchecked")
    public static List<String> getPermissions(String token) {
        Claims claims = getClaims(token);
        if (claims == null) {
            return null;
        }
        return (List<String>) claims.get("permissions");
    }

    /**
     * 从Token中获取角色列表
     * 
     * @param token JWT Token
     * @return 角色列表
     */
    @SuppressWarnings("unchecked")
    public static List<String> getRoles(String token) {
        Claims claims = getClaims(token);
        if (claims == null) {
            return null;
        }
        return (List<String>) claims.get("roles");
    }

    /**
     * 生成密钥（适配低版本）
     */
    private static byte[] generalKey() {  // 低版本直接返回字节数组
        return TOKEN_ENCRY_KEY.getBytes(StandardCharsets.UTF_8);
    }

    public static void main(String[] args) {
        String token = getToken(21L);
        System.out.println("生成的Token：" + token);

        Claims claims = getClaims(token);
        if (claims != null) {
            System.out.println("解析的用户ID：" + claims.get("id"));
            System.out.println("Token状态：" + getStatusDesc(verifyToken(claims)));
        } else {
            System.out.println("Token解析失败");
        }
    }

    private static String getStatusDesc(int status) {
        switch (status) {
            case -1: return "有效且无需刷新";
            case 0: return "可刷新";
            case 1: return "已过期";
            case 2: return "无效";
            default: return "未知状态";
        }
    }
}